package system

import (
	"errors"
	"mytest/models"
	"mytest/models/request"
	"mytest/until"
	"strconv"

	"gorm.io/gorm"
)

// 添加菜单
func AddBaseMenu(db *gorm.DB, menu models.SysBaseMenu) (err error) {
	if !errors.Is(db.Where("name = ?", menu.Name).First(&models.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
		err = errors.New("存在重复name，请修改name")
		return
	}
	err = db.Create(&menu).Error
	return err
}

//查看一个菜单
func GetBaseMenu(db *gorm.DB, id uint) (err error, menu *models.SysBaseMenu) {
	var menus models.SysBaseMenu
	err = db.Model(&models.SysBaseMenu{}).Preload("Parameters").Where("id = ?", id).First(&menus).Error
	return err, &menus
}

//删除菜单
func DeleteBaseMenu(db *gorm.DB, id uint) error {
	var count int64
	err := db.Model(&models.SysBaseMenu{}).Where("parent_id=?", id).Count(&count).Error
	if err != nil {
		return err
	}
	if count > 0 {
		return errors.New("存在子菜单！")
	}

	//第一步先删除外键 parameter
	err = db.Delete(&models.SysBaseMenuParameter{}, "sys_base_menu_id = ?", id).Error
	if err != nil {
		return err
	}

	//再删关联
	var tmp models.SysBaseMenu
	err = db.Model(&models.SysBaseMenu{}).Preload("SysAuthoritys").Where("id = ?", id).First(&tmp).Error
	if err != nil {
		return err
	}
	err = db.Model(&tmp).Association("SysAuthoritys").Delete(&tmp.SysAuthoritys)
	if err != nil {
		return err
	}
	//再删自己
	self := models.SysBaseMenu{ID: id}
	err = db.Model(&models.SysBaseMenu{}).Delete(&self).Error
	if err != nil {
		return err
	}
	return nil
}

//更新菜单,主要更新非关联字段
func UpdateMenu(db *gorm.DB, menu models.SysBaseMenu) (error, *models.SysBaseMenu) {
	var oldMenu models.SysBaseMenu
	if menu.Name != "" {
		err := db.Where("id = ?", menu.ID).Find(&oldMenu).Error
		if err != nil {
			return err, nil
		}
		if oldMenu.Name != menu.Name {
			if !errors.Is(db.Where("id <> ? AND name = ?", menu.ID, menu.Name).First(&models.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {

				return errors.New("存在相同name修改失败"), nil
			}
		}
	}
	if len(menu.Parameters) != 0 {
		db.Model(&models.SysBaseMenuParameter{}).Where("sys_base_menu_id = ?", menu.ID).Delete(&menu.Parameters)
	}
	err := db.Model(&menu).Updates(&menu).Error
	if err != nil {
		return err, nil
	}
	err = db.Where("id = ?", menu.ID).Find(&oldMenu).Error
	if err != nil {
		return err, nil
	}
	return nil, &oldMenu
}

// 获取 所有的菜单, 为什么能全部取出来呢，因为儿子跟父亲都在一张表，不需要预加载
func GetAllMenus(db *gorm.DB) (error, []models.SysBaseMenu) {
	var allmenus []models.SysBaseMenu
	//map
	treeMap := make(map[string][]models.SysBaseMenu)
	err := db.Order("sort").Preload("Parameters").Find(&allmenus).Error
	if err != nil {
		return err, nil
	}
	for _, v := range allmenus {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	RootMenu := treeMap["0"]
	for i := range RootMenu {
		pushMenuChild(&RootMenu[i], treeMap)
	}
	return nil, RootMenu
}

// 获取 所有的菜单
func GetMenuList(db *gorm.DB, req request.MenuList) (error, []models.SysBaseMenu, int64) {
	db = db.Model(models.SysBaseMenu{})
	if req.Path != "" {
		db = db.Where("path like ?", until.Fuzzy(req.Path))
	}
	var count int64
	err := db.Count(&count).Error
	if err != nil {
		return err, nil, 0
	}

	var menus []models.SysBaseMenu
	if req.Desc {
		err := db.Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Order(req.OrderKey).Preload("Parameters").Find(&menus).Error
		if err != nil {
			return err, nil, 0
		}
	} else {
		err := db.Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Preload("Parameters").Find(&menus).Error
		if err != nil {
			return err, nil, 0
		}
	}
	return nil, menus, count
}

//想要儿子，就得自己做爸爸
func pushMenuChild(curMenu *models.SysBaseMenu, treeMap map[string][]models.SysBaseMenu) {
	curID := strconv.Itoa(int(curMenu.ID))
	curMenu.Children = treeMap[curID]
	for i := range curMenu.Children {
		pushMenuChild(&curMenu.Children[i], treeMap)
	}
}

//把儿子装入平级列表里面
func pushMenuId(menus *[]models.SysBaseMenu, allMenus []models.SysBaseMenu, cur models.SysBaseMenu) {
	*menus = append(*menus, cur)
	for i, v := range allMenus {
		id, _ := strconv.Atoi(v.ParentId)
		if uint(id) == cur.ID {
			pushMenuId(menus, allMenus, allMenus[i])
		}
	}

}

//查看当前的角色 的所有菜单，不分父亲和孩子，列表结构
func GetMenuAuthority(db *gorm.DB, authId string) (err error, menus []models.SysBaseMenu) {
	//查出所有的
	var allMenus []models.SysBaseMenu
	err = db.Model(&models.SysBaseMenu{}).Preload("Parameters").Order("sort").Find(&allMenus).Error
	if err != nil {
		return err, nil
	}

	//然后查出第一层的
	var self models.SysAuthority
	err = db.Model(&models.SysAuthority{}).Preload("SysBaseMenus").Where("authority_id= ?", authId).
		First(&self).Error
	if err != nil {
		return err, nil
	}

	for _, c := range self.SysBaseMenus {
		//c 的儿子装进去
		pushMenuId(&menus, allMenus, c)

	}

	return err, menus
}

//用户的动态的菜单树，显示在侧面,树形结构， 这个缺点 就是 只要有1级菜单，1级菜单的2级菜单都能找到
func GetMenusTreeForUser(db *gorm.DB, authId string) (error, []models.SysBaseMenu) {
	var self models.SysAuthority
	var menus []models.SysBaseMenu
	//var allMenus []models.SysBaseMenu
	//先查出自己的第一层的菜单
	err := db.Model(&models.SysAuthority{}).Preload("SysBaseMenus").Where("authority_id= ?", authId).
		First(&self).Error
	if err != nil {
		return err, nil
	}
	//self 的菜单是平行的，所以这里只需要根目录，去除子目录
	tmpMenu := make([]models.SysBaseMenu, 0)
	childMenu := make([]models.SysBaseMenu, 0)
	for _, v := range self.SysBaseMenus {
		if v.ParentId == "0" {
			tmpMenu = append(tmpMenu, v)
		} else {
			childMenu = append(childMenu, v)
		}
	}
	self.SysBaseMenus = tmpMenu

	//map
	treeMap := make(map[string][]models.SysBaseMenu)
	//
	////查出所有的
	//err = db.Model(&models.SysBaseMenu{}).Preload("Parameters").Order("sort").Find(&allMenus).Error
	//if err != nil {
	//	return err, nil
	//}

	for _, v := range childMenu {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	//按照层层查找孩子，先给上外键

	//for i, c := range self.SysBaseMenus {
	//	for _, v := range allMenus {
	//		if v.ID == c.ID {
	//			self.SysBaseMenus[i].Parameters = v.Parameters
	//			break
	//		}
	//	}
	//}

	menus = self.SysBaseMenus
	for i := range menus {
		pushMenuChild(&menus[i], treeMap)
	}
	return nil, menus
}
